home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 July / EnigmA AMIGA RUN 20 (1997)(G.R. Edizioni)(IT)[!][issue 1997-07 & 08][EAR-CD IV].iso / earcd / biz / dbase / db3_4src.lha / db3.4 / dbparser.c < prev    next >
C/C++ Source or Header  |  1997-02-01  |  22KB  |  858 lines

  1. /* dbparser.c, -an RFFparser for db */
  2.  
  3. #include <exec/lists.h>
  4. #include <exec/types.h>
  5. #include <exec/memory.h>
  6. #include <proto/exec.h>
  7. #include <proto/utility.h>
  8. #include <proto/dos.h>
  9. #include <clib/alib_protos.h>        /* NewList() */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <dos.h>
  14.  
  15.  
  16. #include "db.h"
  17. #include "dbparser.h"
  18. #include "dbGUI.h"
  19. #include "dbRexx.h"    /* Only for the handling of the RXPORTNAME tag */
  20.  
  21. #define BUFSIZE 65536
  22.  
  23. #define Rewind(fp) Seek(fp, 0, OFFSET_BEGINNING)
  24.  
  25. char *RFFTagNames[] = {
  26.     "dummy",
  27.     "@RFF",
  28.     "TYPE",
  29.     "FLEN",
  30.     "LNAM",
  31.     "NAME",
  32.     "SIZE",
  33.     "OFFS",
  34.     "NEXT",
  35.     "TABSIZE",
  36.     "RXFILE",
  37.     "RXSTRING",
  38.     "AUTORXFILE",
  39.     "AUTORXSTRING",
  40.     "NEWRECORDRXFILE",
  41.     "NEWRECORDRXSTRING",
  42.     "FTYP",
  43.     "CENT",
  44.     "SFMT",
  45.     "RXPORTNAME",
  46.     "PLACE",
  47.     "ROWS",
  48.     "XPOS",
  49.     "YPOS",
  50.     NULL
  51. };
  52.  
  53. BPTR InFile;
  54.  
  55. void DeleteTag(struct RFFTag *ot)
  56. {
  57.     if (ot) {
  58.         if (ot->Name) FreeMem(ot->Name,strlen(ot->Name)+1);
  59.         if (ot->Data) FreeMem(ot->Data,strlen(ot->Data)+1);
  60.         FreeMem(ot,sizeof(struct RFFTag));
  61.     }
  62. }
  63.  
  64. void DeleteRFFLine(struct RFFLine *ol)
  65. {
  66.     if (ol) {
  67.         if (ol->Line) FreeMem(ol->Line,strlen(ol->Line)+1);
  68.         FreeMem(ol,sizeof(struct RFFLine));
  69.     }
  70. }
  71.  
  72. struct RFFLine *NewRFFLine(const char *line)
  73. {
  74.     /* holds unknown RFF lines */
  75.     struct RFFLine *nl;
  76.  
  77.     if (!(nl = AllocMem(sizeof(struct RFFLine),0))) return NULL;
  78.     if (!(nl->Line = AllocMem(strlen(line)+1,0))) {
  79.         DeleteRFFLine(nl);
  80.         return NULL;
  81.     }
  82.     nl->mln.mln_Pred = NULL;
  83.     nl->mln.mln_Succ = NULL;
  84.     strcpy(nl->Line,line);
  85.  
  86.     return nl;
  87. }
  88.  
  89. struct RFFTag *NewTag(const char *name, int nlen, const char *data, int dlen)
  90. {
  91.     struct RFFTag *nt;
  92.     int i;
  93.  
  94.     if (!(nt = AllocMem(sizeof(struct RFFTag),MEMF_CLEAR))) return NULL;
  95.     if (!(nt->Name = AllocMem(nlen+1,0))) {
  96.         DeleteTag(nt);
  97.         return NULL;
  98.     }
  99.     if (!(nt->Data = AllocMem(dlen+1,0))) {
  100.         DeleteTag(nt);
  101.         return NULL;
  102.     }
  103.  
  104.     stccpy(nt->Name,name,nlen+1);
  105.     stccpy(nt->Data,data,dlen+1);
  106.     nt->ID = UNKNOWN;
  107.  
  108.     for(i=1; RFFTagNames[i]; i++)
  109.         if (!Stricmp((STRPTR)nt->Name,(STRPTR)RFFTagNames[i])) {
  110.             nt->ID = i;
  111.             break;
  112.         }
  113.     return nt;
  114. }
  115.  
  116.  
  117. struct FldInfo *NewFldInfo(void)
  118. {
  119.     /* Allocates and initializes a FldInfo struct with default values */
  120.     struct FldInfo *f;
  121.  
  122.     if (!(f = AllocMem(sizeof(struct FldInfo),0))) return NULL;
  123.     NewList((struct List *)&f->FldTags);
  124.     f->Next = NULL;
  125.     f->Len = DEFMAXFLDLEN;
  126.     /* f->Type = something */
  127.     return f;
  128. }
  129.  
  130. /* // Nice, but later on maybe. See DeletePro()
  131. void DeleteRxInfo(struct RxInfo *ri)
  132. {
  133.     struct RFFTag *ot;
  134.     while (ot = (struct RFFTag *)RemHead((struct List *)&ri->RxTags))
  135.         DeleteTag(ot);
  136.     FreeMem(ri, sizeof(struct RxInfo));
  137. }
  138. */
  139.  
  140. struct RxInfo *NewRxInfo(void)
  141. {
  142.     /* Allocates and initializes an RxInfo struct with default values */
  143.     struct RxInfo *ri;
  144.  
  145.     if (ri = AllocMem(sizeof(struct RxInfo),0)) {
  146.         NewList((struct List *)&ri->RxTags);
  147.         ri->Next = NULL;
  148.     }
  149.     return ri;
  150. }
  151.  
  152. void DeleteVisFldInfo(struct VisFldInfo *vf)
  153. {
  154.     struct RFFTag *ot;
  155.     if (!vf) return;
  156.     if (vf->CEnt) FreeMem(vf->CEnt, (vf->NEnt+1)*sizeof(char *));
  157.  
  158.     while (ot = (struct RFFTag *)RemHead((struct List *)&vf->VisTags))
  159.         DeleteTag(ot);
  160.     FreeMem(vf, sizeof(struct VisFldInfo));
  161. }
  162.  
  163. struct VisFldInfo *NewVisFldInfo(void)
  164. {
  165.     /* Allocates and initializes a VisFldInfo struct with default values */
  166.     struct VisFldInfo *vf;
  167.     struct IntuiText label = { 1,0,JAM1,0,0,NULL,NULL,NULL };
  168.     
  169.     if (!(vf = AllocMem(sizeof(struct VisFldInfo),0))) return NULL;
  170.     
  171.     NewList((struct List *)&vf->VisTags);
  172.     vf->Next = NULL;
  173.     vf->Gadget = NULL;
  174.     vf->Name[0] = '\0';
  175.     vf->Offset = 0;
  176.     vf->VisLen = 25;
  177.     vf->VisSep = '\n';
  178.     vf->Code = 0;
  179.     vf->CEnt = NULL;
  180.     vf->NEnt = 0;
  181.     
  182.     vf->Label = label;
  183.     vf->Label.IText = vf->Name;
  184.  
  185.     return vf;
  186. }
  187.  
  188. /* Support functions for RFFOut */
  189. struct RFFTag *FirstTag(struct MinList *list)
  190. {
  191.     struct RFFTag *tag = (struct RFFTag *)list->mlh_Head;
  192.     if (!tag->mln.mln_Succ) return NULL;    /* The MinList node */
  193.     return tag;
  194. }
  195.  
  196. struct RFFTag *NextTag(struct RFFTag *tag)
  197. {
  198.     tag = (struct RFFTag *)tag->mln.mln_Succ;
  199.     if (!tag->mln.mln_Succ) return NULL;    /* The MinList node */
  200.     return tag;
  201. }
  202.  
  203. struct RFFTag *NextSameTag(struct RFFTag *tag)
  204. {
  205.     short int oldID = tag->ID;
  206.  
  207.     for (;;) {
  208.         tag = (struct RFFTag *)tag->mln.mln_Succ;
  209.         if (!tag->mln.mln_Succ) return NULL;    /* The MinList node */
  210.         if (tag->ID == oldID) return tag;
  211.     }
  212. }
  213.  
  214. struct VisFldInfo *CopyVisFldInfo(struct VisFldInfo *vf)
  215. {
  216.     struct RFFTag *tag, *nt;
  217.     struct VisFldInfo *newvf;
  218.     int i;
  219.  
  220.     if (!(newvf = NewVisFldInfo())) return NULL;
  221.  
  222.     *newvf = *vf;    /* Shallow copy. We have to do more than that */
  223.     newvf->Label.IText = newvf->Name;
  224.  
  225.     NewList((struct List *)&newvf->VisTags);
  226.     newvf->CEnt = NULL;
  227.  
  228.     for (tag = FirstTag(&vf->VisTags); tag; tag = NextTag(tag)) {
  229.         if (!(nt = NewTag(tag->Name, strlen(tag->Name), tag->Data, strlen(tag->Data)))) {
  230.             DeleteVisFldInfo(newvf);
  231.             return NULL;
  232.         }
  233.         else AddTail((struct List *)&newvf->VisTags, (struct Node *)nt);
  234.     }
  235.  
  236.     if (tag = SearchTag(CurrentPro, newvf, NULL, CENT)) {
  237.         if (!(newvf->CEnt =
  238.          AllocMem((vf->NEnt+1)*sizeof(char *), 0)))
  239.              {
  240.                 DeleteVisFldInfo(newvf);
  241.                 return NULL;
  242.              }
  243.         for (i=0; tag ;i++, tag = NextSameTag(tag))
  244.             newvf->CEnt[i] = tag->Data;
  245.         newvf->CEnt[i] = NULL;    /* Nullterm cycleentrylist */
  246.     }
  247.     return newvf;
  248. }
  249.  
  250.  
  251. struct RFFTag *CreateAndAddTag(struct MinList *list, short int id, char *newdata)
  252. {
  253.     struct RFFTag *tag;
  254.  
  255.     if (!(tag = NewTag(RFFTagNames[id], strlen(RFFTagNames[id]),
  256.                              newdata, strlen(newdata)))) return NULL;
  257.     AddTail((struct List *)list, (struct Node *)tag);
  258.     return tag;
  259. }
  260.  
  261.  
  262. struct RFFTag *UpdateTag(struct MinList *list, short int id, char *newdata)
  263. {
  264.     /* Updates tag with ID=id in RFFTaglist list. Creates tag if missing */
  265.     /* Returns updated tag or NULL if memory error */
  266.  
  267.     struct RFFTag *tag;
  268.  
  269.     if (!(tag = FindTag(list, id))) {             /* Create new tag */
  270.         if (!(tag = NewTag(RFFTagNames[id], strlen(RFFTagNames[id]),
  271.                                  newdata, strlen(newdata)))) return NULL;
  272.         AddTail((struct List *)list, (struct Node *)tag);
  273.     }
  274.     else {    /* old tag found */
  275.         int dlen = strlen(newdata);
  276.         char *to;
  277.         if (!(to = AllocMem(dlen+1,0))) return NULL;
  278.         if (tag->Data) FreeMem(tag->Data,strlen(tag->Data)+1);
  279.         tag->Data = to;
  280.         stccpy(tag->Data,newdata,dlen+1);
  281.     }
  282.     return tag;
  283. }
  284.  
  285. void WriteVisTags(struct VisFldInfo *vf)
  286. {
  287.     /* Copy information from vf to vf's tags */
  288.     /* i.e. write vf's Name, Offset, VisLen & VisSep to the name, offs, size & next tags */
  289.  
  290.     char buf[10];    /* Well enough */
  291.  
  292.     UpdateTag(&vf->VisTags, NAME, vf->Name);
  293.     sprintf(buf, "%d", vf->Offset);
  294.     UpdateTag(&vf->VisTags, OFFS, buf);
  295.     sprintf(buf, "%d", vf->VisLen);
  296.     UpdateTag(&vf->VisTags, SIZE, buf);
  297.  
  298.     switch (vf->VisSep) {
  299.         case ' ':
  300.             UpdateTag(&vf->VisTags, NEXT, STR_SPACE); break;
  301.         case '\t':
  302.             UpdateTag(&vf->VisTags, NEXT, STR_TAB); break;
  303.         case '\f':
  304.             UpdateTag(&vf->VisTags, NEXT, STR_PARA); break;
  305.         case '\n':
  306.             UpdateTag(&vf->VisTags, NEXT, "nl"); break;
  307.     }
  308. }
  309.  
  310.  
  311. int ReadVisTags(struct Pro *Pr, struct VisFldInfo *vf)
  312. {
  313.     /* Parse vf's tags and fill vf. If information is incorrect, return RFF_ERR */
  314.     /* Information is incorrect when there is no corresponding field to an offset, */
  315.     /* or when there is a cycle gadget with no cycle entries. */
  316.  
  317.     struct RFFTag *nt;
  318.     struct FldInfo *f;
  319.     int i;
  320.  
  321.     if (nt = FindTag(&vf->VisTags, OFFS))
  322.         vf->Offset = atoi(nt->Data);
  323.         
  324.     if (nt = SearchTag(Pr, vf, NULL, SIZE)) vf->VisLen = atoi(nt->Data);
  325.     if (nt = SearchTag(Pr, vf, NULL, NEXT)) {
  326.         if (!Stricmp(nt->Data,"space")) vf->VisSep = ' ';
  327.         else if (!Stricmp(nt->Data,"tab")) vf->VisSep = '\t';
  328.         else if (!Stricmp(nt->Data,"para")) vf->VisSep = '\f';
  329.     }
  330.  
  331.     /* Delete old cycle array if there was one */
  332.     if (vf->CEnt) {
  333.         FreeMem(vf->CEnt, (vf->NEnt+1)*sizeof(char *));
  334.         vf->CEnt = NULL;
  335.         vf->NEnt = 0;
  336.     }
  337.  
  338.     if (nt = SearchTag(Pr, vf, NULL, FTYP)) {    /* Build new cycle array */
  339.         if (!Stricmp(nt->Data,"cycle")) {
  340.             if (nt = SearchTag(Pr, vf, NULL, CENT)) {
  341.                 for (; nt; ++vf->NEnt, nt = NextSameTag(nt));
  342.                 /* Now vf->NEnt holds the number of cycleentries */
  343.                 if (nt = SearchTag(Pr, vf, NULL, CENT)) {
  344.                     if (!(vf->CEnt =
  345.                      AllocMem((vf->NEnt+1)*sizeof(char *), 0)))
  346.                         return MEM_ERR;
  347.                     for (i=0; nt ;i++, nt = NextSameTag(nt))
  348.                         vf->CEnt[i] = nt->Data;
  349.                     vf->CEnt[i] = NULL;    /* Nullterm cycleentrylist */
  350.                 }
  351.             }
  352.             else return RFF_ERR;    /* There must be atleast one choice */
  353.         }
  354.     }
  355.     f = GetFldInfo(Pr, vf->Offset);
  356.     if (nt = FindTag(&vf->VisTags, NAME))
  357.         stccpy(vf->Name, nt->Data, FIELDNAMELENGTH);
  358.     else if (f) strcpy(vf->Name,f->Name);
  359.  
  360.     if (!f) return RFF_ERR; /* Finally check that there is a corresponding FldInfo */
  361.     return 0;
  362. }
  363.  
  364. /* End of support functions */
  365.  
  366.  
  367. struct RFFTag *FindTag(struct MinList *list, short int id)
  368. {
  369.     struct RFFTag *tag;
  370.     for (tag = (struct RFFTag *)list->mlh_Head; tag->mln.mln_Succ;
  371.      tag = (struct RFFTag *)tag->mln.mln_Succ) if (id == tag->ID) return tag;
  372.     return NULL;
  373. }
  374.  
  375. static struct RFFTag *FindTags(struct MinList *list, short tag1ID, short tag2ID)
  376. {
  377.     struct RFFTag *tag;
  378.     if (!(tag = FindTag(list, tag1ID)))
  379.         if (tag2ID) tag = FindTag(list, tag2ID);
  380.     return tag;
  381. }
  382.  
  383. struct RFFTag *SearchTags(struct Pro *Pr, struct VisFldInfo *vf, Where *where, short tag1ID, short tag2ID)
  384. {
  385.     struct RFFTag *tag;
  386.     Where dummydest;
  387.     if (!where) where = &dummydest;
  388.  
  389.     /* Find the current VisualField */
  390.     if (!vf && !(vf = GetVisFldInfo(Pr->CurrentLayout, LastGad))) return NULL;
  391.  
  392.     if (tag = FindTags(&vf->VisTags, tag1ID, tag2ID)) *where = VIEW_LOCAL;
  393.     else if (tag = FindTags(&Pr->CurrentLayout->LayTags, tag1ID, tag2ID)) *where = VIEW_GLOBAL;
  394.     else if (tag = FindTags(&GetFldInfo(Pr, vf->Offset)->FldTags, tag1ID, tag2ID)) *where = PRO_LOCAL;
  395.     else if (tag = FindTags(&CurrentPro->ProTags, tag1ID, tag2ID)) *where = PRO_GLOBAL;
  396.  
  397.     return tag;
  398. }
  399.  
  400. struct RFFTag *SearchTag(struct Pro *Pr, struct VisFldInfo *vf, Where *where, short tagID)
  401. {
  402.     struct RFFTag *tag;
  403.     Where dummydest;
  404.     if (!where) where = &dummydest;
  405.  
  406.     /* Find the current VisualField */
  407.     if (!vf && !(vf = GetVisFldInfo(Pr->CurrentLayout, LastGad))) return NULL;
  408.  
  409.     if (tag = FindTag(&vf->VisTags, tagID)) *where = VIEW_LOCAL;
  410.     else if (tag = FindTag(&Pr->CurrentLayout->LayTags, tagID)) *where = VIEW_GLOBAL;
  411.     else if (tag = FindTag(&GetFldInfo(Pr, vf->Offset)->FldTags, tagID)) *where = PRO_LOCAL;
  412.     else if (tag = FindTag(&CurrentPro->ProTags, tagID)) *where = PRO_GLOBAL;
  413.  
  414.     return tag;
  415. }
  416.  
  417.  
  418. struct FldInfo *GetFldInfo(struct Pro *Pr, short Offset)
  419. {
  420.     /* Returns pointer to a FldInfo struct, returns NULL if not found */
  421.  
  422.     struct FldInfo *f, *old=NULL;
  423.     int i;
  424.     if (!Pr) return NULL; /* Safety, Should never happen */
  425.     for (f = Pr->FirstFldInfo, i=0; i<=Offset; f = f->Next, i++) {
  426.         if (!f) return NULL;
  427.         else old = f;
  428.     }
  429.     return old;
  430. }
  431.  
  432. struct VisFldInfo *GetVisFldInfo(struct Layout *Lay, struct Gadget *g)
  433. {
  434.     struct VisFldInfo *vf = Lay->FirstVisFldInfo;
  435.     for (;vf ;vf = vf->Next) if (vf->Gadget == g) break;
  436.     return vf;
  437. }
  438.  
  439. __inline char *SkipSpc(const char *s)
  440. {
  441.     /* Returns a pointer to the first non-space character or a pointer to NULL */
  442.     /* A comma is also considered a space */
  443.     /* if no non-space characters are found */
  444.     
  445.     while (*s && (*s == ' ' || *s == ',')) s++;
  446.     return s;
  447. }
  448.  
  449.  
  450. struct RFFTag *GetTag(const char **cursor)
  451. {
  452.     /* Takes a comma and tabseparated RFFLine and returns an RFFTag */
  453.     /* Starts searching from cursor which is also updated after each call */
  454.     /* Will return NULL when hitting a \t or \0 character */
  455.  
  456.     struct RFFTag *nt = NULL;
  457.     const char *brkchar, *nameptr, *dataptr = NULL;
  458.     int namelen, datalen;
  459.  
  460.     *cursor = SkipSpc(*cursor);
  461.  
  462.     if (**cursor == '\t') { 
  463.         (*cursor)++;
  464.         return NULL;
  465.     }
  466.     
  467.     /* Name part*/
  468.     if (brkchar = strpbrk(*cursor,"= ")) {
  469.         namelen = brkchar - *cursor;
  470.         nameptr = *cursor;
  471.         *cursor = brkchar+1;
  472.  
  473.         /* Data part */
  474.         if (**cursor == '\"') {    /* "Quotes" */
  475.             if (brkchar = strpbrk(++(*cursor),"\"")) {    /* The other " */
  476.                 datalen = brkchar - *cursor;
  477.                 dataptr = *cursor;
  478.                 *cursor = brkchar+1;
  479.             }
  480.         }
  481.         else {    /* No quotes */
  482.             if (brkchar = strpbrk(*cursor,", \t\n")) datalen = brkchar - *cursor;
  483.             else datalen = strlen(*cursor);
  484.             dataptr = *cursor;
  485.             *cursor = brkchar;
  486.         }
  487.         if (dataptr) nt = NewTag(nameptr,namelen,dataptr,datalen);
  488.     }
  489.     return nt;
  490. }
  491.  
  492.  
  493. /*
  494. BOOL PutTag(struct RFFTag *tag, BPTR fp)
  495. {
  496.     if (FPuts(fp, tag->Name) == EOF) return FALSE;
  497.     if (FPutC(fp, '=') == EOF) return FALSE;
  498.     if (tag->Data && strlen(tag->Data)) {
  499.         if (FPuts(fp, tag->Data) == EOF) return FALSE;
  500.     }
  501.     else if (FPuts(fp, "\"\"") == EOF) return FALSE;
  502.  
  503.     return TRUE;
  504. }
  505. */
  506.  
  507. BOOL PutTag(struct RFFTag *tag, BPTR fp)
  508. {
  509.     BOOL quotes = FALSE;
  510.     if (FPuts(fp, tag->Name) == EOF) return FALSE;
  511.     if (FPutC(fp, '=') == EOF) return FALSE;
  512.     if (tag->Data && strlen(tag->Data)) {
  513.         if (strpbrk(tag->Data," ,\t")) {
  514.             quotes = TRUE;
  515.             if (FPutC(fp, '"') == EOF) return FALSE;
  516.         }
  517.         if (FPuts(fp, tag->Data) == EOF) return FALSE;
  518.         if (quotes) if (FPutC(fp, '"') == EOF) return FALSE;
  519.     }
  520.     else if (FPuts(fp, "\"\"") == EOF) return FALSE;
  521.  
  522.     return TRUE;
  523. }
  524.  
  525.  
  526. BOOL PutTags(struct RFFTag *tag, BPTR fp)
  527. {
  528.     if (!PutTag(tag,fp)) return FALSE;
  529.     while (tag = NextTag(tag)) {
  530.         if (FPutC(fp, ',') == EOF) return FALSE;
  531.         if (!PutTag(tag,fp)) return FALSE;
  532.     }
  533.     return TRUE;
  534. }
  535.  
  536. BOOL RFFOut(struct Pro *Pr, BPTR fp)
  537. {
  538.     /* Writes all RFFtags to disk */
  539.  
  540.     struct Layout *lay;
  541.     struct FldInfo *f;
  542.     struct RxInfo *ri;
  543.     struct VisFldInfo *vf;
  544.     struct RFFLine *rl;
  545.     struct RFFTag *tag;
  546.  
  547.     /* Save schema:
  548.         ProTags, all FldTags, \n 
  549.         RxTags, \n
  550.         for all layouts: LayTags, all VisTags \n
  551.         (UnknownLines, \n)
  552.     */
  553.  
  554. ProTags:
  555.     if (!(tag = FirstTag(&Pr->ProTags))) goto RxTags;
  556.     if (!PutTags(tag,fp)) return FALSE;
  557.  
  558. FldTags:
  559.     for (f = Pr->FirstFldInfo; f; f = f->Next) {
  560.         if (FPutC(fp, '\t') == EOF) return FALSE;
  561.         if (!(tag = FirstTag(&f->FldTags))) continue;
  562.         if (!PutTags(tag,fp)) return FALSE;
  563.     }
  564.     if (FPutC(fp, '\n') == EOF) return FALSE;
  565.  
  566. RxTags:
  567.     for (ri = Pr->FirstRxInfo; ri; ri = ri->Next) {
  568.         if (ri != Pr->FirstRxInfo && FPutC(fp, '\t') == EOF) return FALSE;
  569.         if (!(tag = FirstTag(&ri->RxTags))) continue;
  570.         if (!PutTags(tag,fp)) return FALSE;
  571.     }
  572.     if (Pr->FirstRxInfo && FPutC(fp, '\n') == EOF) return FALSE;
  573.  
  574. Layouts:
  575.     for (lay = Pr->FirstLayout; lay; lay = lay->NextLayout) {
  576. Laytags:
  577.         if (!(tag = FirstTag(&lay->LayTags))) continue;
  578.         if (!PutTags(tag,fp)) return FALSE;
  579. VisTags:
  580.         for (vf = lay->FirstVisFldInfo; vf; vf = vf->Next) {
  581.             if (FPutC(fp, '\t') == EOF) return FALSE;
  582.             if (!(tag = FirstTag(&vf->VisTags))) continue;
  583.             if (!PutTags(tag,fp)) return FALSE;
  584.         }
  585.         if (FPutC(fp, '\n') == EOF) return FALSE;
  586.     }
  587.  
  588. UnknownLines:
  589.     for (rl = (struct RFFLine *)Pr->UnknownLines.mlh_Head; rl->mln.mln_Succ;
  590.      rl = (struct RFFLine *)rl->mln.mln_Succ) {
  591.          if (FPuts(fp, rl->Line) == EOF) return FALSE;
  592.      }
  593.  
  594.     return TRUE;
  595. }
  596.  
  597.  
  598. BOOL DoASCIIParsing(struct Pro *Pr)
  599. {
  600.     /* Build default VisFldInfos if file lacks recognizable RFF lines */
  601.  
  602.     struct VisFldInfo *vf, *oldv = NULL;
  603.     struct FldInfo *f;
  604.     short off;
  605.  
  606.     if (!NewLayout(Pr)) return FALSE;
  607.  
  608.     /* Get the layoutname from the project name */
  609.     stccpy(Pr->CurrentLayout->Name, Pr->Name, LAYOUTNAMELENGTH);
  610.  
  611.     /* Add an @rff=1.1 and a type=form tag */
  612.     CreateAndAddTag(&Pr->CurrentLayout->LayTags, RFF, "1.1");
  613.     CreateAndAddTag(&Pr->CurrentLayout->LayTags, TYPE, "form");
  614.     
  615.     for (f = Pr->FirstFldInfo, off = 0; f; f = f->Next, off++) {
  616.         if (!(vf = NewVisFldInfo())) return FALSE;
  617.         strcpy(vf->Name,f->Name);            /* Same name as the internal names */
  618.         vf->Offset = off;
  619.         WriteVisTags(vf);
  620.     
  621.         /* Finally fix the links */
  622.         if (!oldv) {
  623.             oldv = vf;
  624.             Pr->CurrentLayout->FirstVisFldInfo = vf;
  625.         }
  626.         else {    /* Fix backward links */
  627.             oldv->Next = vf;
  628.             oldv = vf;
  629.         }
  630.     }
  631.     return TRUE;
  632. }
  633.  
  634. int DoParsing(BPTR fp, struct Pro *Pr, char *buffer)
  635. {
  636.     /* Do the actual parsing */
  637.     /* Return number of RFF lines found (both known and unknown */
  638.     /* Negative numbers indicate errors */
  639.  
  640.     char *cursor;
  641.     int n,len;
  642.     struct VisFldInfo *vf, *oldv;
  643.     struct FldInfo *f, *old = NULL;
  644.     struct RFFTag *nt;
  645.     struct RFFLine *rl;
  646.     short defoffset;
  647.     char *brkchar;
  648.     int ret;
  649.     
  650.     /* Read first line and build the FldInfo list */
  651.     if (!FGets(fp, buffer,BUFSIZE)) return FILE_ERR;
  652.     cursor = buffer;
  653.     while (brkchar = strpbrk(cursor,"\t\n")) {
  654.         len = brkchar - cursor;
  655.         if (len >= FIELDNAMELENGTH) return FILE_ERR;
  656.         if (!(f = NewFldInfo())) return MEM_ERR;
  657.         stccpy(f->Name, cursor,len+1);
  658.  
  659.         if (!old) {
  660.             old = f;
  661.             Pr->FirstFldInfo = f;
  662.         }
  663.         else {    /* Fix previous links */
  664.             old->Next = f;
  665.             old = f;
  666.         }
  667.         cursor += len+1;
  668.     }
  669.     
  670.     /* Parse the RFF lines */
  671.  
  672.     for (n=0;;++n) {
  673.         if (!FGets(fp, buffer,BUFSIZE)) return n;
  674.         cursor=buffer;
  675.  
  676.         /* In RFF1.x The first two tags has to be @RFF and TYPE */
  677.         if (!(nt = GetTag(&cursor))) return n;    /* Not an RFF line */
  678.         if (nt->ID != RFF) {                            /* Not an RFF line */
  679.             DeleteTag(nt);
  680.             return n;
  681.         }
  682.         if (Strnicmp(nt->Data,"1.",2)) {                        /* Unknown RFF line */
  683.             DeleteTag(nt);
  684.             if (rl = NewRFFLine(buffer))
  685.                 AddTail((struct List *)&Pr->UnknownLines, (struct Node *)rl);
  686.             continue;
  687.         }
  688.         /* It's at least an RFF 1.1 line... */
  689.         AddTail((struct List *)&Pr->ProTags, (struct Node *)nt);
  690.  
  691.         if (!(nt = GetTag(&cursor))) return n;            /* no more tags?? */
  692.         if (nt->ID != TYPE) {                                /* Unknown RFF line */
  693.             DeleteTag(nt);
  694.             DeleteTag((struct RFFTag *)RemTail((struct List *)&Pr->ProTags));
  695.             if (rl = NewRFFLine(buffer))
  696.              AddTail((struct List *)&Pr->UnknownLines, (struct Node *)rl);
  697.             continue;
  698.         }
  699.         
  700.         /* Handle the different types */
  701.  
  702.         if (!Stricmp(nt->Data,"internal")) {
  703.             AddTail((struct List *)&Pr->ProTags, (struct Node *)nt);
  704.         
  705.             /* Add rest of tags till we hit the first \t char */
  706.             while (nt = GetTag(&cursor))
  707.                 AddTail((struct List *)&Pr->ProTags, (struct Node *)nt);
  708.  
  709.             /* Work thru all tags adding information to the FldInfo structs */
  710.             for (f = Pr->FirstFldInfo; f; f = f->Next) {
  711.                 while (nt = GetTag(&cursor)) {
  712.                     AddTail((struct List *)&f->FldTags, (struct Node *)nt);
  713.                 }
  714.                 if (nt = FindTag(&f->FldTags, FLEN)) f->Len = atoi(nt->Data);
  715.             }
  716.  
  717.             /* Change the portname of this project if the RXPORTNAME tag is found */
  718.             if (nt = FindTag(&Pr->ProTags, RXPORTNAME)) {
  719.                 if (MyRexxPort) CloseRexxPort(MyRexxPort);
  720.                 if ((MyRexxPort = SetupRexxPort(nt->Data)) == NULL) return MEM_ERR;
  721.             }
  722.         }
  723.  
  724.         else if (!Stricmp(nt->Data,"form")) {
  725.             if (!NewLayout(Pr)) {
  726.                 DeleteTag(nt);
  727.                 return MEM_ERR;
  728.             }
  729.             AddHead((struct List *)&Pr->CurrentLayout->LayTags, RemTail((struct List *)&Pr->ProTags));
  730.             AddTail((struct List *)&Pr->CurrentLayout->LayTags, (struct Node *)nt);
  731.  
  732.             /* Add rest of tags till we hit the first \t char */
  733.             while (nt = GetTag(&cursor))
  734.                 AddTail((struct List *)&Pr->CurrentLayout->LayTags, (struct Node *)nt);
  735.  
  736.             /* Get the layoutname from the taglist */
  737.             if (nt = FindTag(&Pr->CurrentLayout->LayTags, LNAM))
  738.                 stccpy(Pr->CurrentLayout->Name, nt->Data, LAYOUTNAMELENGTH);
  739.             
  740.             /* Read window position tags */
  741.             {
  742.                 struct RFFTag *xpos, *ypos;
  743.                 if (xpos = FindTag(&Pr->CurrentLayout->LayTags, XPOS))
  744.                     Pr->CurrentLayout->XPos = atoi(xpos->Data);
  745.                 if (ypos = FindTag(&Pr->CurrentLayout->LayTags, YPOS))
  746.                     Pr->CurrentLayout->YPos = atoi(ypos->Data);
  747.             }
  748.             /* Work thru all tags building VisFldInfo structs along the way */
  749.             for (oldv=0, defoffset=0;;defoffset++) {
  750.                 if (!(nt = GetTag(&cursor))) break;
  751.                 if (!(vf = NewVisFldInfo())) {
  752.                     DeleteTag(nt);
  753.                     return MEM_ERR;
  754.                 }
  755.                 /* Fix the links now so we don't loose it if some error occurs */
  756.                 if (!oldv) {
  757.                     oldv = vf;
  758.                     Pr->CurrentLayout->FirstVisFldInfo = vf;
  759.                 }
  760.                 else {    /* Fix backward links */
  761.                     oldv->Next = vf;
  762.                     oldv = vf;
  763.                 }
  764.                 
  765.                 AddTail((struct List *)&vf->VisTags, (struct Node *)nt);
  766.                 while (nt = GetTag(&cursor))
  767.                     AddTail((struct List *)&vf->VisTags, (struct Node *)nt);
  768.  
  769.                 /* Add values from the RFF tags */
  770.                 vf->Offset = defoffset;
  771.                 if ((ret = ReadVisTags(Pr, vf)) < 0) return ret;
  772.                 defoffset = vf->Offset;
  773.             }
  774.         }
  775.         else if (!Stricmp(nt->Data,"rxmenu")) {
  776.             struct RxInfo *ri;
  777.             if (!(Pr->FirstRxInfo = NewRxInfo())) return MEM_ERR;
  778.             AddHead((struct List *)&Pr->FirstRxInfo->RxTags, RemTail((struct List *)&Pr->ProTags));
  779.             AddTail((struct List *)&Pr->FirstRxInfo->RxTags, (struct Node *)nt);
  780.             /* Add rest of tags till we hit the first \t char */
  781.             while (nt = GetTag(&cursor))
  782.                 AddTail((struct List *)&Pr->FirstRxInfo->RxTags, (struct Node *)nt);
  783.  
  784.             /* Work thru all tags building RxInfo structs along the way */
  785.             ri = Pr->FirstRxInfo;
  786.             while ((nt = GetTag(&cursor)) && (ri = ri->Next = NewRxInfo())) {
  787.                 AddTail((struct List *)&ri->RxTags, (struct Node *)nt);
  788.                 while (nt = GetTag(&cursor))
  789.                     AddTail((struct List *)&ri->RxTags, (struct Node *)nt);
  790.             }
  791.             if (nt) {
  792.                 DeleteTag(nt);
  793.                 return MEM_ERR;
  794.             }
  795.         }
  796.         else {                                /* Other unknown RFF types */
  797.             if (rl = NewRFFLine(buffer))
  798.                 AddTail((struct List *)&Pr->UnknownLines, (struct Node *)rl);
  799.             DeleteTag((struct RFFTag *)RemTail((struct List *)&Pr->ProTags));
  800.             DeleteTag(nt);
  801.             continue;
  802.         }
  803.     }
  804. }
  805.  
  806.  
  807. BOOL IsBinary(BPTR fp)
  808. {
  809.     /* If the file contains at least one \0 character it's considered binary */
  810.     int d;
  811.     Rewind(fp);                    // The last FGets() might have read past the file
  812.     while ((d = FGetC(fp)) != EOF)
  813.         if (!d) return TRUE;
  814.     return FALSE;
  815. }
  816.  
  817.  
  818. int RFFParse(struct Pro *Pr, BPTR fp)
  819. {
  820.     /* Checks if fp is a valid RFF file. If so. The RFF tags will be parsed */
  821.     /* and inserted into the project. */
  822.     /* When finished, the next character read will be the first non-RFF line */
  823.  
  824.     char *buffer;
  825.     int n;    /* Retval from DoParsing(). Number of RFF lines in file */
  826.  
  827.     /* Allocate enough space for one line */
  828.     if (!(buffer = AllocMem(BUFSIZE,0))) return MEM_ERR;
  829.  
  830.     n = DoParsing(fp, Pr, buffer);
  831.     Pr->CurrentLayout = Pr->FirstLayout;    
  832.  
  833.     if (n > 0) {    /* Some RFF lines exist */
  834.         Rewind(fp);
  835.         while(1 + n--) FGets(fp, buffer, BUFSIZE);    /* first line and RFF lines */
  836.     }
  837.     else if (n == 0) {
  838.         if (IsBinary(fp)) {
  839.             FreeMem(buffer,BUFSIZE);
  840.             return FILE_ERR;
  841.         }
  842.         else {                                                /* An ASCII file */
  843.             Rewind(fp);
  844.             FGets(fp, buffer,BUFSIZE);                    /* Skip 1st line */
  845.         }
  846.     }
  847.     else {
  848.         FreeMem(buffer,BUFSIZE);                        /* Some error */
  849.         return n;
  850.     }
  851.  
  852.     FreeMem(buffer,BUFSIZE);
  853.     if (!Pr->FirstLayout)         /* There has to be at least one layout */
  854.         if (!DoASCIIParsing(Pr)) return MEM_ERR; /* Build default VisFldInfos */
  855.  
  856.     return 0;
  857. }
  858.